package service

import (
	"context"
	"errors"
	"fmt"
	"time"
	jwt "github.com/star-find-cloud/star-chat/pkg/jwt"
	log "github.com/star-find-cloud/star-chat/pkg/logger"
	"github.com/star-find-cloud/star-chat/user/domain"
	"github.com/star-find-cloud/star-chat/user/repo"
	"github.com/star-find-cloud/star-chat/utils"
)

type UserServiceImpl struct {
	repo repo.UserRepo
}

func NewUserServiceImpl(repo repo.UserRepo) *UserServiceImpl {
	return &UserServiceImpl{repo: repo}
}

func (s *UserServiceImpl) Create(ctx context.Context, user *domain.User) (int64, error) {
	return s.repo.Create(ctx, user)
}

func (s *UserServiceImpl) Register(ctx context.Context, user *domain.User) (string, int64, error) {
	phoneExist, err := s.IsExistsByPhone(ctx, user.Phone)
	if err != nil {
		log.AppLogger.Errorf("an error occurred in the user repo, err: %v", err)
		return "", 0, err
	}

	if !utils.VerifyEmail(user.Email) {
		return "", 0, errors.New("email format is incorrect")
	}

	emailExist, err := s.IsExistsByEmail(ctx, user.Email)
	if err != nil {
		log.AppLogger.Errorf("an error occurred in the user repo, err: %v", err)
		return "", 0, err
	}
	if phoneExist || emailExist {
		return "", 0, errors.New("phone or email already exists")
	}
	safePasswd, err := utils.BcryptPassword(user.Password)
	if err != nil {
		log.AppLogger.Errorf("password encryption failed: %v", err)
		return "", 0, fmt.Errorf("password encryption failed: %v", err)
	}
	user.Password = safePasswd

	id, err := s.repo.Create(ctx, user)
	if err != nil {
		log.AppLogger.Errorf("create user metadata failed: %v", err)
		return "", 0, err
	}

	fmt.Println("用户注册模块, token 需要在权限系统完善后进行修改, 相关代码在 user_service_impl")
	token, err := jwt.GenerateToken(id, user.Name, 1)
	return token, id, err
}

func (s *UserServiceImpl) Get(ctx context.Context, id int64) (*domain.User, error) {
	user, err := s.repo.GetAll(ctx, id)
	if err != nil {
		log.AppLogger.Errorf("get user all info failed: %v", err)
		return nil, fmt.Errorf("get user info failed: %v", err)
	}
	return user, nil
}

func (s *UserServiceImpl) GetByID(ctx context.Context, id int64) (*domain.User, error) {
	user, err := s.repo.GetByID(ctx, id)
	if err != nil {
		log.AppLogger.Errorf("get user by id failed: %v", err)
		return nil, fmt.Errorf("get user by id failed: %v", err)
	}
	return user, nil
}

func (s *UserServiceImpl) GetByEmail(ctx context.Context, email string) (*domain.User, error) {
	user, err := s.repo.GetByEmail(ctx, email)
	if err != nil {
		log.AppLogger.Errorf("get user by email failed: %v", err)
		return nil, fmt.Errorf("get user by email failed: %v", err)
	}
	return user, nil
}

func (s *UserServiceImpl) GetByPhone(ctx context.Context, phone int64) (*domain.User, error) {
	// 注意：这里需要国家码，暂时使用默认值86
	user, err := s.repo.GetByPhone(ctx, 86, phone)
	if err != nil {
		log.AppLogger.Errorf("get user by phone failed: %v", err)
		return nil, fmt.Errorf("get user by phone failed: %v", err)
	}
	return user, nil
}

func (s *UserServiceImpl) IsExistsByID(ctx context.Context, id int64) (bool, error) {
	exists, err := s.repo.IsExistsByID(ctx, id)
	if err != nil {
		log.AppLogger.Errorf("check user exists by id failed: %v", err)
		return false, fmt.Errorf("check user exists failed: %v", err)
	}
	return exists, nil
}

func (s *UserServiceImpl) IsExistsByPhone(ctx context.Context, phone int64) (bool, error) {
	// 注意：这里需要国家码，暂时使用默认值86
	exists, err := s.repo.IsExistsByPhone(ctx, 86, phone)
	if err != nil {
		log.AppLogger.Errorf("check user exists by phone failed: %v", err)
		return false, fmt.Errorf("check user exists by phone failed: %v", err)
	}
	return exists, nil
}

func (s *UserServiceImpl) IsExistsByEmail(ctx context.Context, email string) (bool, error) {
	exists, err := s.repo.IsExistsByEmail(ctx, email)
	if err != nil {
		log.AppLogger.Errorf("check user exists by email failed: %v", err)
		return false, fmt.Errorf("check user exists by email failed: %v", err)
	}
	return exists, nil
}

func (s *UserServiceImpl) Login(ctx context.Context, id, phone, countryCode int64, email, password string) (*domain.User, error) {
	var user *domain.User
	var err error

	// 根据提供的标识符获取用户信息
	if id > 0 {
		user, err = s.repo.GetByID(ctx, id)
	} else if phone > 0 {
		user, err = s.repo.GetByPhone(ctx, countryCode, phone)
	} else if email != "" {
		user, err = s.repo.GetByEmail(ctx, email)
	} else {
		return nil, errors.New("login identifier is required")
	}

	if err != nil {
		log.AppLogger.Errorf("get user info for login failed: %v", err)
		return nil, fmt.Errorf("login failed: user not found or error occurred")
	}

	// 验证密码
	passwordCorrect, err := s.repo.CheckPassword(ctx, user.ID, password)
	if err != nil {
		log.AppLogger.Errorf("check password failed: %v", err)
		return nil, fmt.Errorf("login failed: password verification error")
	}

	if !passwordCorrect {
		return nil, errors.New("login failed: incorrect password")
	}

	// 检查用户状态
	if user.Status == domain.Disable {
		return nil, errors.New("login failed: account is disabled")
	}

	if user.Status == domain.Suspended {
		return nil, errors.New("login failed: account is suspended")
	}

	return user, nil
}

func (s *UserServiceImpl) Update(ctx context.Context, user *domain.User) error {
	// 检查用户是否存在
	exists, err := s.repo.IsExistsByID(ctx, user.ID)
	if err != nil {
		log.AppLogger.Errorf("check user exists failed: %v", err)
		return fmt.Errorf("update failed: %v", err)
	}
	if !exists {
		return errors.New("update failed: user not found")
	}

	// 如果邮箱有变化，检查邮箱是否已被使用
	if user.Email != "" {
		currentUser, err := s.repo.GetByID(ctx, user.ID)
		if err != nil {
			log.AppLogger.Errorf("get current user info failed: %v", err)
			return fmt.Errorf("update failed: %v", err)
		}

		if currentUser.Email != user.Email {
			emailExists, err := s.repo.IsExistsByEmail(ctx, user.Email)
			if err != nil {
				log.AppLogger.Errorf("check email exists failed: %v", err)
				return fmt.Errorf("update failed: %v", err)
			}
			if emailExists {
				return errors.New("update failed: email already exists")
			}
		}
	}

	err = s.repo.Update(ctx, user)
	if err != nil {
		log.AppLogger.Errorf("update user info failed: %v", err)
		return fmt.Errorf("update failed: %v", err)
	}

	return nil
}

func (s *UserServiceImpl) UpdatePassword(ctx context.Context, id int64, newPassword, oldPassword string) error {
	// 验证旧密码
	passwordCorrect, err := s.repo.CheckPassword(ctx, id, oldPassword)
	if err != nil {
		log.AppLogger.Errorf("check old password failed: %v", err)
		return fmt.Errorf("update password failed: %v", err)
	}

	if !passwordCorrect {
		return errors.New("update password failed: old password is incorrect")
	}

	// 加密新密码
	safePasswd, err := utils.BcryptPassword(newPassword)
	if err != nil {
		log.AppLogger.Errorf("encrypt new password failed: %v", err)
		return fmt.Errorf("update password failed: %v", err)
	}

	// 更新密码
	err = s.repo.UpdatePassword(ctx, id, safePasswd)
	if err != nil {
		log.AppLogger.Errorf("update password failed: %v", err)
		return fmt.Errorf("update password failed: %v", err)
	}

	return nil
}

func (s *UserServiceImpl) UpdatePhone(ctx context.Context, id, phone, countryCode int64) error {
	// 检查手机号是否已被使用
	phoneExists, err := s.repo.IsExistsByPhone(ctx, countryCode, phone)
	if err != nil {
		log.AppLogger.Errorf("check phone exists failed: %v", err)
		return fmt.Errorf("update phone failed: %v", err)
	}

	if phoneExists {
		return errors.New("update phone failed: phone number already exists")
	}

	err = s.repo.UpdatePhone(ctx, id, countryCode, phone)
	if err != nil {
		log.AppLogger.Errorf("update phone failed: %v", err)
		return fmt.Errorf("update phone failed: %v", err)
	}

	return nil
}

func (s *UserServiceImpl) ForgetPassword(ctx context.Context, phone int64, email, password string) error {
	var user *domain.User
	var err error

	// 根据手机号或邮箱获取用户信息
	if phone > 0 {
		// 注意：这里需要国家码，暂时使用默认值86
		user, err = s.repo.GetByPhone(ctx, 86, phone)
	} else if email != "" {
		user, err = s.repo.GetByEmail(ctx, email)
	} else {
		return errors.New("phone or email is required for password reset")
	}

	if err != nil {
		log.AppLogger.Errorf("get user info for password reset failed: %v", err)
		return fmt.Errorf("password reset failed: user not found")
	}

	// 加密新密码
	safePasswd, err := utils.BcryptPassword(password)
	if err != nil {
		log.AppLogger.Errorf("encrypt new password failed: %v", err)
		return fmt.Errorf("password reset failed: %v", err)
	}

	// 更新密码
	err = s.repo.UpdatePassword(ctx, user.ID, safePasswd)
	if err != nil {
		log.AppLogger.Errorf("update password failed: %v", err)
		return fmt.Errorf("password reset failed: %v", err)
	}

	return nil
}

func (s *UserServiceImpl) UpdateStatus(ctx context.Context, id int64, status int64) error {
	// 检查用户是否存在
	exists, err := s.repo.IsExistsByID(ctx, id)
	if err != nil {
		log.AppLogger.Errorf("check user exists failed: %v", err)
		return fmt.Errorf("update status failed: %v", err)
	}
	if !exists {
		return errors.New("update status failed: user not found")
	}

	// 验证状态值是否有效
	if status != int64(domain.Active) && status != int64(domain.Disable) && status != int64(domain.Suspended) {
		return errors.New("update status failed: invalid status value")
	}

	err = s.repo.UpdateStatus(ctx, id, status)
	if err != nil {
		log.AppLogger.Errorf("update user status failed: %v", err)
		return fmt.Errorf("update status failed: %v", err)
	}

	return nil
}

func (s *UserServiceImpl) DeleteByPhone(ctx context.Context, countryCode, phone int64) error {
	// 检查用户是否存在
	exists, err := s.repo.IsExistsByPhone(ctx, countryCode, phone)
	if err != nil {
		log.AppLogger.Errorf("check user exists failed: %v", err)
		return fmt.Errorf("delete failed: %v", err)
	}
	if !exists {
		return errors.New("delete failed: user not found")
	}

	// 先获取用户ID，然后删除
	user, err := s.repo.GetByPhone(ctx, countryCode, phone)
	if err != nil {
		log.AppLogger.Errorf("get user by phone failed: %v", err)
		return fmt.Errorf("delete failed: %v", err)
	}

	err = s.repo.Delete(ctx, user.ID)
	if err != nil {
		log.AppLogger.Errorf("delete user failed: %v", err)
		return fmt.Errorf("delete failed: %v", err)
	}

	return nil
}

func (s *UserServiceImpl) DeleteByEmail(ctx context.Context, email string) error {
	// 检查用户是否存在
	exists, err := s.repo.IsExistsByEmail(ctx, email)
	if err != nil {
		log.AppLogger.Errorf("check user exists failed: %v", err)
		return fmt.Errorf("delete failed: %v", err)
	}
	if !exists {
		return errors.New("delete failed: user not found")
	}

	// 先获取用户ID，然后删除
	user, err := s.repo.GetByEmail(ctx, email)
	if err != nil {
		log.AppLogger.Errorf("get user by email failed: %v", err)
		return fmt.Errorf("delete failed: %v", err)
	}

	err = s.repo.Delete(ctx, user.ID)
	if err != nil {
		log.AppLogger.Errorf("delete user failed: %v", err)
		return fmt.Errorf("delete failed: %v", err)
	}

	return nil
}

func (s *UserServiceImpl) Delete(ctx context.Context, id int64) error {
	// 检查用户是否存在
	exists, err := s.repo.IsExistsByID(ctx, id)
	if err != nil {
		log.AppLogger.Errorf("check user exists failed: %v", err)
		return fmt.Errorf("delete failed: %v", err)
	}
	if !exists {
		return errors.New("delete failed: user not found")
	}

	err = s.repo.Delete(ctx, id)
	if err != nil {
		log.AppLogger.Errorf("delete user failed: %v", err)
		return fmt.Errorf("delete failed: %v", err)
	}

	return nil
}

func (s *UserServiceImpl) CheckEmailVerificationCode(ctx context.Context, email string, verificationCode string) (bool, error) {
	if verificationCode == "" || email == "" {
		return false, errors.New("verification code or email cannot be empty")
	}
	if !utils.VerifyEmail(email) {
		return false, errors.New("email format is incorrect")
	}

	return s.repo.CheckEmailVerificationCode(ctx, email, verificationCode)
}

func (s *UserServiceImpl) BannedUser(ctx context.Context, id int64, time time.Time) error {
	// 检查用户是否存在
	exists, err := s.repo.IsExistsByID(ctx, id)
	if err != nil {
		log.AppLogger.Errorf("check user exists failed: %v", err)
		return fmt.Errorf("ban user failed: %v", err)
	}
	if !exists {
		return errors.New("ban user failed: user not found")
	}

	// 更新用户状态为禁用并设置封禁时间
	err = s.repo.UpdateStatus(ctx, id, int64(domain.Disable))
	if err != nil {
		log.AppLogger.Errorf("update user status failed: %v", err)
		return fmt.Errorf("ban user failed: %v", err)
	}

	// 这里可以添加设置封禁时间的逻辑
	// 例如：s.repo.UpdateBannedTime(ctx, id, time)
	
	return nil
}
